<template>
  <div
      ref="containerRef"
      class="carousel-item-container"
      @mouseleave="handleMouseLeave"
      @mousemove="handleMouseMove"
  >
    <div ref="imgRef" :style="imgPosition" class="carousel-img">
      <ImageLoader
          :placeholder="banner.midImg"
          :src="banner.bigImg"
          @load="showWords"
      ></ImageLoader>
    </div>
    <div ref="titleRef" class="title">{{ banner.title }}</div>
    <div ref="descRef" class="desc">{{ banner.description }}</div>
  </div>
</template>
<script lang="ts" setup>
import ImageLoader from '@/components/ImageLoader/index.vue'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'

defineProps(['banner'])

const titleRef = ref<any>()
const descRef = ref<any>()
const titleWidth = ref(0)
const descWidth = ref(0)
const containerRef = ref<any>()
const imgRef = ref<any>()
const containerSize = ref<any>(null)
const innerSize = ref<any>(null)
const mouseX = ref(0)
const mouseY = ref(0)

const imgPosition = computed(() => {
  if (!containerSize.value || !innerSize.value) {
    return
  }
  // 多出的宽度
  const extraWidth = innerSize.value.width - containerSize.value.width
  // 多出的高度
  const extraHeight = innerSize.value.height - containerSize.value.height
  const left = (-extraWidth / containerSize.value.width) * mouseX.value
  const top = (-extraHeight / containerSize.value.height) * mouseY.value
  return {
    transform: `translate(${left}px, ${top}px)`
  }
})

const center = computed(() => {
  return {
    x: containerSize.value.width / 2,
    y: containerSize.value.height / 2
  }
})

onMounted(() => {
  titleWidth.value = titleRef.value?.clientWidth as number
  descWidth.value = descRef.value?.clientWidth as number
  setSize()
  mouseX.value = center.value.x
  mouseY.value = center.value.y
  window.addEventListener('resize', setSize)
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', setSize)
})

const showWords = () => {
  titleRef.value.style.opacity = '1'
  titleRef.value.style.width = 0
  // 让浏览器重新渲染
  titleRef.value.clientWidth // reflow
  titleRef.value.style.transition = '1s'
  titleRef.value.style.width = titleWidth.value + 'px'

  descRef.value.style.opacity = '1'
  descRef.value.style.width = 0
  // 让浏览器重新渲染
  descRef.value.clientWidth // reflow
  descRef.value.style.transition = '2s 1s'
  descRef.value.style.width = descWidth.value + 'px'
}

const setSize = () => {
  containerSize.value = {
    width: containerRef.value.clientWidth,
    height: containerRef.value.clientHeight
  }

  innerSize.value = {
    width: imgRef.value.clientWidth,
    height: imgRef.value.clientHeight
  }
}

const handleMouseMove = (e: MouseEvent) => {
  const rect = containerRef.value.getBoundingClientRect()
  mouseX.value = e.clientX - rect.left
  mouseY.value = e.clientY - rect.top
}

const handleMouseLeave = () => {
  mouseX.value = center.value.x
  mouseY.value = center.value.y
}
</script>
<style lang="less" scoped>
@import '@/styles/var.less';

.carousel-item-container {
  width: 100%;
  height: 100%;
  color: #fff;
  position: relative;
  overflow: hidden;
}

.carousel-img {
  width: 110%;
  height: 110%;
  position: absolute;
  left: 0;
  top: 0;
  transition: 0.3s;
  z-index: -1;
}

.title,
.desc {
  position: absolute;
  letter-spacing: 3px;
  left: 30px;
  color: #fff;
  text-shadow: 1px 0 0 rgba(0, 0, 0, 0.5), -1px 0 0 rgba(0, 0, 0, 0.5), 0 1px 0 rgba(0, 0, 0, 0.5),
    0 -1px 0 rgba(0, 0, 0, 0.5);
  white-space: nowrap;
  overflow: hidden;
  opacity: 0;
  z-index: 2;
}

.title {
  top: calc(50% - 40px);
  font-size: 2em;
}

.desc {
  top: calc(50% + 20px);
  font-size: 1.2em;
  color: lighten(@gray, 20%);
}
</style>